Skip to content

Add wpdb fallback for wp db query, wp db import, wp db drop, and wp db reset when mysql/mariadb binary is unavailable#320

Draft
swissspidy with Copilot wants to merge 21 commits into
mainfrom
copilot/fix-wp-db-query-fallback
Draft

Add wpdb fallback for wp db query, wp db import, wp db drop, and wp db reset when mysql/mariadb binary is unavailable#320
swissspidy with Copilot wants to merge 21 commits into
mainfrom
copilot/fix-wp-db-query-fallback

Conversation

Copilot AI commented Apr 2, 2026

Copy link
Copy Markdown
Contributor

Several wp db commands currently require the mysql/mariadb CLI binary, causing failures with drop-in database engines (HyperDB, custom drivers) or environments where the binary simply isn't installed. This PR adds automatic fallback to WordPress's $wpdb for all relevant commands.

Changes

src/DB_Command.php

  • is_mysql_binary_available() — probes for the mysql/mariadb binary via /usr/bin/env <binary> --version; result is statically cached
  • maybe_load_wpdb() — loads the minimal WordPress files needed for $wpdb (load.php, compat.php, plugin.php, functions.php, class-wpdb.php), includes any wp-content/db.php drop-in (HyperDB et al.), and falls back to creating a plain wpdb instance with wp-config.php credentials + $table_prefix
  • run_query() — now checks binary availability at the top and, when absent, routes through maybe_load_wpdb() + $wpdb->query() instead of invoking the mysql CLI. This covers drop and reset.
  • query() — after the existing SQLite branch, checks binary availability and routes to the new wpdb path when absent via wpdb_query()
  • wpdb_query() — executes arbitrary SQL via $wpdb; mirrors the mysql-path behaviour (row-count reporting for DML, formatted tabular output for SELECT, --skip-column-names support)
  • import() — when the mysql binary is unavailable, reads the SQL file (or STDIN) and delegates to wpdb_import()
  • wpdb_import() — executes a SQL dump through $wpdb statement-by-statement, applying the same autocommit=0 / unique_checks=0 / foreign_key_checks=0 … COMMIT optimizations as the mysql path (unless --skip-optimization is passed)
  • split_sql_statements() — splits a SQL string into individual statements using a state-machine parser that correctly handles single-quoted strings, double-quoted strings, -- line comments, and /* */ block comments

features/db-query.feature

Added a @require-mysql-or-mariadb scenario that shadows the real binary with a fake exit 127 script via PATH prepending, then asserts the query succeeds and the debug message confirms the fallback was taken.

features/db.feature

Added @require-mysql-or-mariadb scenarios for wp db drop and wp db reset that shadow the binary with a fake exit 127 script and assert each command succeeds via the wpdb path (verified via the Query via wpdb: debug line).

features/db-import.feature

Added a @require-mysql-or-mariadb scenario that exports a real SQL dump first, then shadows the binary and re-imports it, asserting success and the MySQL/MariaDB binary not available, falling back to wpdb for import. debug message.

Note: wp db create is not covered by the wpdb fallback because wpdb requires the target database to already exist in order to establish a connection — a from-scratch create (no DB yet) cannot be handled via vanilla wpdb.

Summary by CodeRabbit

  • New Features

    • Database commands now automatically fall back to WordPress database connectivity when MySQL or MariaDB client tools are unavailable.
    • Added fallback support for database queries, SQL imports, database drops, and resets.
    • Query results and command output remain compatible with existing command-line formatting.
  • Bug Fixes

    • Database operations can now complete successfully in environments without installed MySQL/MariaDB binaries.
    • Added clearer diagnostic warnings when fallback execution is used.

@codecov

codecov Bot commented Apr 2, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 78.57143% with 39 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/DB_Command.php 78.57% 39 Missing ⚠️

📢 Thoughts on this report? Let us know!

Copilot AI changed the title [WIP] Fix wp db query to fallback using WPDB Add wpdb fallback for wp db query when mysql/mariadb binary is unavailable Apr 2, 2026
Copilot AI requested a review from swissspidy April 2, 2026 21:31
@swissspidy

This comment was marked as resolved.

This comment was marked as resolved.

Copilot AI changed the title Add wpdb fallback for wp db query when mysql/mariadb binary is unavailable Add wpdb fallback for wp db query, wp db import, wp db create, wp db drop, and wp db reset when mysql/mariadb binary is unavailable Apr 3, 2026
Comment thread features/db-query.feature Outdated
@swissspidy

This comment was marked as resolved.

This comment was marked as resolved.

Copilot AI changed the title Add wpdb fallback for wp db query, wp db import, wp db create, wp db drop, and wp db reset when mysql/mariadb binary is unavailable Add wpdb fallback for wp db query, wp db import, wp db drop, and wp db reset when mysql/mariadb binary is unavailable Apr 3, 2026
Copilot AI requested a review from swissspidy April 3, 2026 09:12
Comment thread features/db.feature Outdated

This comment was marked as resolved.

@swissspidy

This comment was marked as resolved.

Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>

This comment was marked as resolved.

@swissspidy

This comment was marked as resolved.

…query/import

Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>

This comment was marked as resolved.

@swissspidy

This comment was marked as resolved.

Copilot AI and others added 2 commits July 14, 2026 11:34
…_import()

Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>
…y output

Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>

This comment was marked as resolved.

@swissspidy

This comment was marked as resolved.

Copilot AI and others added 2 commits July 14, 2026 14:29
…...*/)

Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>
…p comments

Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>

This comment was marked as resolved.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a fallback execution path for several wp db subcommands when the mysql/mariadb client binary is not available, and extends Behat coverage to validate the fallback behavior by shadowing the client binaries via PATH.

Changes:

  • Added mysql/mariadb binary availability detection and routed wp db query / wp db import (and DDL via run_query()) through a PHP-based fallback when unavailable.
  • Implemented SQL execution/import helpers (including SQL dump statement splitting) for the fallback path.
  • Added Behat scenarios that simulate missing client binaries and assert fallback success + debug output.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.

File Description
src/DB_Command.php Adds mysql binary probing, mysqli-based fallback execution/import, and a SQL statement splitter for imports.
features/db.feature Adds scenarios verifying wp db drop and wp db reset succeed when mysql/mariadb binaries are shadowed.
features/db-query.feature Adds scenario verifying wp db query succeeds and logs fallback when mysql/mariadb binaries are shadowed.
features/db-import.feature Adds scenario verifying wp db import succeeds and logs fallback when mysql/mariadb binaries are shadowed.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/DB_Command.php
Comment on lines +608 to +610
WP_CLI::debug( 'MySQL/MariaDB binary not available, falling back to wpdb.', 'db' );
$this->wpdb_query( $query, $assoc_args );
return;
Comment thread src/DB_Command.php
Comment on lines +2532 to +2536
protected function wpdb_query( $query, $assoc_args = [] ) {
$conn = $this->get_db_connection();

$skip_column_names = Utils\get_flag_value( $assoc_args, 'skip-column-names', false );
$is_row_modifying_query = (bool) preg_match( '/\b(UPDATE|DELETE|INSERT|REPLACE(?!\s*\()|LOAD DATA)\b/i', $query );
Comment thread src/DB_Command.php
Comment on lines +2590 to +2593
protected function wpdb_import( $sql_content, $assoc_args = [] ) {
$conn = $this->get_db_connection();

$skip_optimization = Utils\get_flag_value( $assoc_args, 'skip-optimization', false );
Comment thread src/DB_Command.php
Comment on lines +2699 to +2702
if ( '-' === $char && '-' === $next && ! $in_single_quote && ! $in_double_quote ) {
$in_line_comment = true;
continue;
}
Comment thread src/DB_Command.php
Comment on lines +942 to +961
if ( ! $this->is_mysql_binary_available() ) {
if ( '-' === $result_file ) {
$sql_content = stream_get_contents( STDIN );
if ( false === $sql_content ) {
WP_CLI::error( 'Failed to read from STDIN.' );
}
$result_file = 'STDIN';
} else {
if ( ! is_readable( $result_file ) ) {
WP_CLI::error( sprintf( 'Import file missing or not readable: %s', $result_file ) );
}
$sql_content = file_get_contents( $result_file );
if ( false === $sql_content ) {
WP_CLI::error( sprintf( 'Could not read import file: %s', $result_file ) );
}
}

WP_CLI::debug( 'MySQL/MariaDB binary not available, falling back to wpdb for import.', 'db' );
$this->wpdb_import( (string) $sql_content, $assoc_args );
WP_CLI::success( sprintf( "Imported from '%s'.", $result_file ) );
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 97ae9620-fa12-494d-9f24-e6d3decb32c9

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • ✅ Review completed - (🔄 Check again to review again)
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch copilot/fix-wp-db-query-fallback

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (3)
src/DB_Command.php (1)

1977-1997: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Uses a fresh connection per DDL call — fine for single calls, costly in clean()'s loop.

run_query() now routes every run_query() caller through this method when the binary is unavailable, including clean(), which calls run_query() once per table (Lines 235-244). Each call opens and closes a brand-new mysqli connection just to run one DROP TABLE. For large installs with many tables this multiplies connection overhead unnecessarily.

♻️ Suggested direction

Accept an optional existing mysqli connection (or expose a connection-reuse variant) so callers that issue many DDL statements in a loop (like clean()) can reuse a single connection instead of opening one per statement.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/DB_Command.php` around lines 1977 - 1997, Update run_query_via_mysqli()
to accept an optional existing mysqli connection, creating and closing its own
connection only when one is not provided. Modify clean() to obtain one reusable
connection before its table-drop loop and pass it to each run_query_via_mysqli()
call, then close it after the loop while preserving existing error handling.
features/db-query.feature (1)

158-183: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Scenario correctly matches the fallback's debug message; consider adding SQL-mode-compat coverage.

This scenario is well-formed and the previously requested env PATH=... fix is already applied. Given the critical SQL-mode-compatibility gap identified in wpdb_query()/wpdb_import() (src/DB_Command.php), consider adding a fallback scenario analogous to "wp db query adapts the SQL mode by default without a separate mode probe" (Lines 100-113) but using the fake-bin technique, so a fix to that gap is actually exercised by CI.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@features/db-query.feature` around lines 158 - 183, Add a fake-bin fallback
scenario in features/db-query.feature that verifies wp db query adapts SQL mode
by default without a separate mode probe, using the same PATH override and
unavailable mysql/mariadb binaries as the current scenario. Ensure the
assertions exercise the compatibility behavior implemented by
DB_Command::wpdb_query() or DB_Command::wpdb_import(), including the expected
query result and debug output.
features/db-import.feature (1)

72-99: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Scenario structure is correct but doesn't reproduce the known regression.

This test imports a plain export on what is likely a lenient-SQL-mode CI database, so it wouldn't fail even with the missing SQL-mode-compat statement in wpdb_import() (see src/DB_Command.php). Consider mirroring "wp db import loads a dump containing legacy zero-date values" (Lines 323-344) but through the fake-bin/mysqli fallback path, since that's the exact scenario that previously surfaced "Invalid default value for 'comment_date'" per the PR history.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@features/db-import.feature` around lines 72 - 99, The fallback scenario
should import a dump containing legacy zero-date values so it exercises the
SQL-mode compatibility logic in DB_Command::wpdb_import(), rather than importing
a plain export. Adapt the existing fake-bin/mysql and fake-bin/mariadb
unavailable setup to use the zero-date dump content and retain assertions for
successful import and the fallback warning.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/DB_Command.php`:
- Around line 2593-2629: Apply get_sql_mode_compat_statement( $assoc_args ) to
the fallback connection before executing SQL in both src/DB_Command.php lines
2593-2629 within wpdb_import() and lines 2535-2583 within wpdb_query(); each
site requires the same compatibility statement before the split statements or
query runs.
- Around line 2008-2013: Update the run_query() fallback around
is_mysql_binary_available() so database creation does not route through
run_query_via_mysqli() without a selected database. Exclude the create()
operation from this fallback, preserving the existing mysqli behavior for other
queries, or explicitly align the command documentation and design with
supporting create() through that path.
- Around line 2481-2524: Update get_db_connection() to use the command’s
effective CLI database username and password values, including --dbuser and
--dbpass overrides, instead of always reading DB_USER and DB_PASSWORD. Handle
mysqli connection exceptions so failures reach the existing WP_CLI::error()
path, and ensure fallback query operations similarly tolerate or catch mysqli
exceptions before relying on connect_errno/query checks.

---

Nitpick comments:
In `@features/db-import.feature`:
- Around line 72-99: The fallback scenario should import a dump containing
legacy zero-date values so it exercises the SQL-mode compatibility logic in
DB_Command::wpdb_import(), rather than importing a plain export. Adapt the
existing fake-bin/mysql and fake-bin/mariadb unavailable setup to use the
zero-date dump content and retain assertions for successful import and the
fallback warning.

In `@features/db-query.feature`:
- Around line 158-183: Add a fake-bin fallback scenario in
features/db-query.feature that verifies wp db query adapts SQL mode by default
without a separate mode probe, using the same PATH override and unavailable
mysql/mariadb binaries as the current scenario. Ensure the assertions exercise
the compatibility behavior implemented by DB_Command::wpdb_query() or
DB_Command::wpdb_import(), including the expected query result and debug output.

In `@src/DB_Command.php`:
- Around line 1977-1997: Update run_query_via_mysqli() to accept an optional
existing mysqli connection, creating and closing its own connection only when
one is not provided. Modify clean() to obtain one reusable connection before its
table-drop loop and pass it to each run_query_via_mysqli() call, then close it
after the loop while preserving existing error handling.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 147dfdef-c9e6-4d69-9dda-8223e5fcbc7f

📥 Commits

Reviewing files that changed from the base of the PR and between 4f7635d and 6051f7f.

📒 Files selected for processing (4)
  • features/db-import.feature
  • features/db-query.feature
  • features/db.feature
  • src/DB_Command.php

Comment thread src/DB_Command.php
Comment on lines +2008 to +2013
if ( ! $this->is_mysql_binary_available() ) {
WP_CLI::debug( "Query via mysqli: {$query}", 'db' );
$this->run_query_via_mysqli( $query );
return;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect relevant methods in src/DB_Command.php
grep -nE 'function (create|run_query|run_query_via_mysqli|get_db_connection|is_mysql_binary_available)' -n src/DB_Command.php

# Show the relevant sections with line numbers
sed -n '1,180p' src/DB_Command.php
echo '---'
sed -n '1960,2060p' src/DB_Command.php
echo '---'
sed -n '2060,2145p' src/DB_Command.php

Repository: wp-cli/db-command

Length of output: 11488


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the connection helper and surrounding logic.
sed -n '2470,2575p' src/DB_Command.php

# Show any references to create() / unsupported / fallback in this file.
grep -nE 'unsupported|fallback|mysqli|CREATE DATABASE|run_query_via_mysqli|maybe_load_sqlite_dropin' src/DB_Command.php

Repository: wp-cli/db-command

Length of output: 5535


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '2470,2575p' src/DB_Command.php
echo '---'
grep -nE 'unsupported|fallback|mysqli|CREATE DATABASE|run_query_via_mysqli|maybe_load_sqlite_dropin' src/DB_Command.php

Repository: wp-cli/db-command

Length of output: 5539


wp db create still goes through the mysqli fallback. create() calls run_query(), and the no-binary path uses run_query_via_mysqli() with no selected database, so CREATE DATABASE will succeed there. Either exclude create() from this fallback or update the command docs/design to say it’s supported.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/DB_Command.php` around lines 2008 - 2013, Update the run_query() fallback
around is_mysql_binary_available() so database creation does not route through
run_query_via_mysqli() without a selected database. Exclude the create()
operation from this fallback, preserving the existing mysqli behavior for other
queries, or explicitly align the command documentation and design with
supporting create() through that path.

Comment thread src/DB_Command.php
Comment on lines +2481 to +2524
/**
* Open a mysqli connection using the WordPress database credentials.
*
* Used as a fallback when the mysql/mariadb binary is not available.
* Parses DB_HOST the same way WordPress does (host:port, host:/socket, :/socket).
*
* @param bool $select_db Whether to select DB_NAME on connect. Pass false for
* server-level DDL (DROP/CREATE DATABASE).
* @return mysqli Connected mysqli instance. Calls WP_CLI::error() on failure.
*/
protected function get_db_connection( $select_db = true ) {
$db_host = DB_HOST;
$port = null;
$socket = null;

if ( ':' === substr( $db_host, 0, 1 ) ) {
$socket = substr( $db_host, 1 );
$db_host = 'localhost';
} else {
$parts = explode( ':', $db_host, 2 );
$db_host = $parts[0];
if ( isset( $parts[1] ) ) {
$port_or_socket = trim( $parts[1] );
if ( '' !== $port_or_socket && '/' === $port_or_socket[0] ) {
$socket = $port_or_socket;
} elseif ( '' !== $port_or_socket ) {
$port = (int) $port_or_socket;
}
}
}

$port_value = null !== $port ? $port : 0;
$socket_value = null !== $socket ? $socket : '';
$database = $select_db ? DB_NAME : '';

// phpcs:ignore WordPress.DB.RestrictedClasses.mysql__mysqli -- direct mysqli required as fallback when mysql binary is unavailable.
$conn = new mysqli( $db_host, DB_USER, DB_PASSWORD, $database, $port_value, $socket_value );

if ( $conn->connect_errno ) {
WP_CLI::error( sprintf( 'Failed to connect to the database: %s', $conn->connect_error ) );
}

return $conn;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Repo root: '; pwd
printf '\nRelevant PHP files around DB_Command:\n'
git ls-files 'src/DB_Command.php' 'composer.json' 'phpcs.xml.dist' 'README*' 'docs/**' 'bin/**' | sed 's#^`#-` #'

printf '\nSearch for PHP version requirements:\n'
rg -n --hidden -S "PHP ?8\.1|minimum PHP|PHP_VERSION|Requires PHP|php >=|php:" composer.json README* docs src bin .github 2>/dev/null || true

printf '\nSearch for mysqli_report / get_db_connection / dbuser usage:\n'
rg -n -S "mysqli_report|get_db_connection\(|dbuser|dbpass|DB_USER|DB_PASSWORD" src/DB_Command.php src 2>/dev/null || true

Repository: wp-cli/db-command

Length of output: 12267


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'src/DB_Command.php outline:\n'
ast-grep outline src/DB_Command.php --view expanded | sed -n '1,260p'

printf '\nTargeted slices around relevant methods:\n'
sed -n '2400,2605p' src/DB_Command.php | cat -n

Repository: wp-cli/db-command

Length of output: 11393


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'composer.json (version-related keys):\n'
if [ -f composer.json ]; then
  python3 - <<'PY'
import json
from pathlib import Path
p = Path("composer.json")
data = json.loads(p.read_text())
for k in ["require", "require-dev", "config", "scripts"]:
    if k in data:
        print(f"\n[{k}]")
        print(data[k])
PY
fi

printf '\nphpcs.xml.dist snippets:\n'
if [ -f phpcs.xml.dist ]; then
  rg -n -S "php_version|PHP|testVersion|runtime" phpcs.xml.dist || true
fi

Repository: wp-cli/db-command

Length of output: 1340


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'README and package metadata around requirements/support:\n'
rg -n -S "PHP 7|PHP 8|minimum supported|requires PHP|WP-CLI|require-php|testVersion|7\.2-|8\.1|mysqli" README.md composer.json phpcs.xml.dist src 2>/dev/null || true

printf '\nREADME top section:\n'
sed -n '1,120p' README.md | cat -n

Repository: wp-cli/db-command

Length of output: 5985


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'README and package metadata around requirements/support:\n'
rg -n -S "PHP 7|PHP 8|minimum supported|requires PHP|WP-CLI|require-php|testVersion|7\\.2-|8\\.1|mysqli" README.md composer.json phpcs.xml.dist src 2>/dev/null || true

printf '\nREADME top section:\n'
sed -n '1,120p' README.md | cat -n

Repository: wp-cli/db-command

Length of output: 5985


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1968,2615p' src/DB_Command.php | cat -n | sed -n '1,280p'

Repository: wp-cli/db-command

Length of output: 11990


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
p = Path("src/DB_Command.php")
lines = p.read_text().splitlines()
for start,end in [(1978,2028),(2528,2610)]:
    print(f"\n--- {start}-{end} ---")
    for i in range(start-1, min(end, len(lines))):
        print(f"{i+1:5d}: {lines[i]}")
PY

Repository: wp-cli/db-command

Length of output: 5329


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show where the command-level assoc args are consumed for the mysql binary path.
python3 - <<'PY'
from pathlib import Path
lines = Path("src/DB_Command.php").read_text().splitlines()
for start,end in [(470,560),(575,650),(930,1015)]:
    print(f"\n--- {start}-{end} ---")
    for i in range(start-1, min(end, len(lines))):
        print(f"{i+1:5d}: {lines[i]}")
PY

Repository: wp-cli/db-command

Length of output: 11555


🌐 Web query:

WP-CLI minimum supported PHP version current release 2025

💡 Result:

As of July 21, 2026, the current version of WP-CLI is 2.12.0 [1][2]. The official minimum supported PHP version for WP-CLI is PHP 7.2.24 or later [2][3]. While WP-CLI v2.12.0 maintained compatibility with older PHP versions (including 5.6) through various workarounds [1], official documentation confirms the current requirement as PHP 7.2.24+ [3][4]. Developers have noted that future major releases (such as the planned 3.0.0) intend to formalize this 7.2.24+ requirement to remove legacy compatibility code [1][5].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Search for any mysqli_report or DB bootstrap tweaks in the repo:\n'
rg -n -S "mysqli_report|MYSQLI_REPORT|wpdb|wp-db.php|database.*bootstrap|bootstrap.*database" . 2>/dev/null || true

Repository: wp-cli/db-command

Length of output: 7349


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
for p in Path('.').rglob('*'):
    if p.is_file() and p.suffix in {'.php', '.md', '.json', '.dist', '.txt'}:
        text = p.read_text(errors='ignore')
        if 'mysqli_report' in text or 'MYSQLI_REPORT' in text or 'wp-db.php' in text:
            print(p)
PY

Repository: wp-cli/db-command

Length of output: 502


Handle mysqli exceptions and pass CLI credentials through the fallback.

  • The package still supports PHP 7.2.24+, so PHP 8.1+ installs can hit mysqli’s default strict mode here and throw before the connect_errno / query() checks run.
  • get_db_connection() also still reads DB_USER / DB_PASSWORD directly, so --dbuser / --dbpass are ignored when the binary fallback is used.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/DB_Command.php` around lines 2481 - 2524, Update get_db_connection() to
use the command’s effective CLI database username and password values, including
--dbuser and --dbpass overrides, instead of always reading DB_USER and
DB_PASSWORD. Handle mysqli connection exceptions so failures reach the existing
WP_CLI::error() path, and ensure fallback query operations similarly tolerate or
catch mysqli exceptions before relying on connect_errno/query checks.

Comment thread src/DB_Command.php
Comment on lines +2593 to +2629
protected function wpdb_import( $sql_content, $assoc_args = [] ) {
$conn = $this->get_db_connection();

$skip_optimization = Utils\get_flag_value( $assoc_args, 'skip-optimization', false );

if ( ! $skip_optimization ) {
$conn->query( 'SET autocommit = 0' );
$conn->query( 'SET unique_checks = 0' );
$conn->query( 'SET foreign_key_checks = 0' );
}

$statements = $this->split_sql_statements( $sql_content );

foreach ( $statements as $statement ) {
$statement = trim( $statement );
if ( '' === $statement ) {
continue;
}
if ( ! $conn->query( $statement ) ) {
$error = $conn->error;
if ( ! $skip_optimization ) {
$conn->query( 'ROLLBACK' );
}
$conn->close();
WP_CLI::error( "Import failed: {$error}" );
}
}

if ( ! $skip_optimization ) {
$conn->query( 'COMMIT' );
$conn->query( 'SET autocommit = 1' );
$conn->query( 'SET unique_checks = 1' );
$conn->query( 'SET foreign_key_checks = 1' );
}

$conn->close();
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔴 Critical | 🏗️ Heavy lift

Missing SQL-mode compatibility is one root cause shared by both mysqli fallback executors. Neither wpdb_import() nor wpdb_query() applies get_sql_mode_compat_statement() on the fallback connection, unlike the CLI path's --init-command. This is the specific regression the PR objectives describe ("Invalid default value for 'comment_date'" on WordPress 4.9, and continued failures across versions).

  • src/DB_Command.php#L2593-L2629: in wpdb_import(), run $this->get_sql_mode_compat_statement( $assoc_args ) on the connection before executing the split statements.
  • src/DB_Command.php#L2535-L2583: in wpdb_query(), run the same compatibility statement on the connection before executing $query.
🧰 Tools
🪛 ast-grep (0.44.1)

[error] 2598-2598: Prevent SQL queries built from unsanitized input
Context: $conn->query( 'SET autocommit = 0' )
Note: [CWE-89] Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection').

(sql-injection-php)


[error] 2599-2599: Prevent SQL queries built from unsanitized input
Context: $conn->query( 'SET unique_checks = 0' )
Note: [CWE-89] Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection').

(sql-injection-php)


[error] 2600-2600: Prevent SQL queries built from unsanitized input
Context: $conn->query( 'SET foreign_key_checks = 0' )
Note: [CWE-89] Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection').

(sql-injection-php)


[error] 2610-2610: Prevent SQL queries built from unsanitized input
Context: $conn->query( $statement )
Note: [CWE-89] Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection').

(sql-injection-php)


[error] 2613-2613: Prevent SQL queries built from unsanitized input
Context: $conn->query( 'ROLLBACK' )
Note: [CWE-89] Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection').

(sql-injection-php)


[error] 2621-2621: Prevent SQL queries built from unsanitized input
Context: $conn->query( 'COMMIT' )
Note: [CWE-89] Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection').

(sql-injection-php)


[error] 2622-2622: Prevent SQL queries built from unsanitized input
Context: $conn->query( 'SET autocommit = 1' )
Note: [CWE-89] Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection').

(sql-injection-php)


[error] 2623-2623: Prevent SQL queries built from unsanitized input
Context: $conn->query( 'SET unique_checks = 1' )
Note: [CWE-89] Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection').

(sql-injection-php)


[error] 2624-2624: Prevent SQL queries built from unsanitized input
Context: $conn->query( 'SET foreign_key_checks = 1' )
Note: [CWE-89] Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection').

(sql-injection-php)

📍 Affects 1 file
  • src/DB_Command.php#L2593-L2629 (this comment)
  • src/DB_Command.php#L2535-L2583
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/DB_Command.php` around lines 2593 - 2629, Apply
get_sql_mode_compat_statement( $assoc_args ) to the fallback connection before
executing SQL in both src/DB_Command.php lines 2593-2629 within wpdb_import()
and lines 2535-2583 within wpdb_query(); each site requires the same
compatibility statement before the split statements or query runs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

query shouldn't require mysql/mariadb cli tools

3 participants